package com.gitee.zzh.controller;

import com.gitee.zzh.codegenerator.CodeFromTemplateFile;
import com.gitee.zzh.codegenerator.CustomCode;
import com.gitee.zzh.codegenerator.DefaultCustomCodeImpl;
import com.gitee.zzh.codegenerator.ParamInfo;
import com.gitee.zzh.common.ConfigUtil;
import com.gitee.zzh.common.DBUtil;
import com.gitee.zzh.common.StrUtil;
import com.gitee.zzh.common.DatabaseConfig;
import com.gitee.zzh.common.AlertUtil;

import javafx.scene.control.*;
import org.apache.log4j.Logger;

import java.io.File;
import java.net.URL;
import java.util.*;

import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.cell.TextFieldTreeCell;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.stage.DirectoryChooser;
import javafx.util.Callback;

/**
 * 首页的控制器
 */
public class IndexController extends BaseController {
	private final Logger LOG = Logger.getLogger(this.getClass());

	private DatabaseConfig updateOfDatabaseConfig;
	private DatabaseConfig databaseConfig;

	// ========================fxml控件============================
	/** 数据库连接 */
	@FXML
	private Label lblConnection;
	/** 使用说明 */
	@FXML
	private Label lblInstructions;
	/** 数据树列表 */
	@FXML
	private TreeView<String> tvDataBase;
	/** 存放目录 */
	@FXML
	private TextField txtProjectPath;
	@FXML
	private TextField txtMainPath;
	/** 数据库表名 */
	@FXML
	private TextField txtTableName;
	/** 文件名前缀 */
	@FXML
	private TextField txtEntityName;
	@FXML
	private TextField txtBasePackage;
	@FXML
	private TextField txtCorePackage;
	@FXML
	private ComboBox<String> cboNameCnt;
	@FXML
	private TextField txtAliasName;
	@FXML
	private TextField txtConnName;
	/** 字符编码格式 */
	@FXML
	private ComboBox<String> cboCodeFormat;
	@FXML
	private ComboBox<String> cboStringType;

	@Override
	public void initialize(URL location, ResourceBundle resources) {
		LOG.debug("初始化首页...");
		final int ml = 20;// 左外边距
		// 初始化图标连接与配置信息
		ImageView lblConnImage = new ImageView("image/computer.png");
		lblConnImage.setFitHeight(40);
		lblConnImage.setFitWidth(40);
		lblConnection.setGraphic(lblConnImage);
		lblConnection.setOnMouseClicked(this::onConnection);

		ImageView lblInstructionsImage = new ImageView("image/instructions.png");
		lblInstructionsImage.setFitHeight(40);
		lblInstructionsImage.setFitWidth(40);
		lblInstructions.setGraphic(lblInstructionsImage);
		lblInstructions.setOnMouseClicked(this::onInstructions);
		ImageView lblSettingImage = new ImageView("image/setting.png");
		lblSettingImage.setFitHeight(40);
		lblSettingImage.setFitWidth(40);

		cboCodeFormat.setEditable(true);
		cboCodeFormat.getItems().addAll("UTF-8", "GBK", "UTF-16", "UTF-32", "GB2312", "GB18030", "ISO-8859-1");
		cboCodeFormat.setValue("UTF-8");
		LOG.debug("初始化首页成功!");
		try {
			// 加载左边数据库树
			initTVDataBase();
			loadTVDataBase();
			LOG.debug("加载所有数据库到左侧树集成功!");
		} catch (Exception e1) {
			LOG.error("加载所有数据库到左侧树集失败!!!", e1);
			AlertUtil.showErrorAlert(e1.getMessage());
		}

		cboStringType.setEditable(true);
		cboStringType.getItems().addAll("resultMapList", "columnListWithAlias", "whereIfList", "whereIds", "insertValueList", "setIfList",
				"fieldVOList", "fieldEntityList", "entityToVOSetterFields", "voToEntitySetterFields");
		cboStringType.setValue("resultMapList");
		cboNameCnt.setEditable(true);
		cboNameCnt.getItems().addAll("1", "2", "3", "4");
		cboNameCnt.setValue("4");
	}

	/**
	 * 右边数据库树与事件
	 */
	@SuppressWarnings("unchecked")
	public void initTVDataBase() {
		LOG.debug("加载左侧数据库树与事件....");
		tvDataBase.setShowRoot(false);
		tvDataBase.setRoot(new TreeItem<>());
		Callback<TreeView<String>, TreeCell<String>> defaultCellFactory = TextFieldTreeCell.forTreeView();
		tvDataBase.setCellFactory((TreeView<String> tv) -> {
			TreeCell<String> cell = defaultCellFactory.call(tv);
			cell.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
				int level = tvDataBase.getTreeItemLevel(cell.getTreeItem());
				TreeCell<String> treeCell = (TreeCell<String>) event.getSource();
				TreeItem<String> treeItem = treeCell.getTreeItem();
				if (level == 1) {
					final ContextMenu contextMenu = new ContextMenu();
					MenuItem item0 = new MenuItem("打开连接");
					item0.setOnAction(event1 -> {
						LOG.debug("执行打开数据库连接....");
						DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData();
						try {
							List<String> tables = DBUtil.getTableNames(selectedConfig);
							if (!tables.isEmpty()) {
								ObservableList<TreeItem<String>> children = cell.getTreeItem().getChildren();
								children.clear();
								for (String tableName : tables) {
									TreeItem<String> newTreeItem = new TreeItem<>();
									ImageView imageView = new ImageView("image/table.png");
									imageView.setFitHeight(16);
									imageView.setFitWidth(16);
									newTreeItem.setGraphic(imageView);
									newTreeItem.setValue(tableName);
									children.add(newTreeItem);
								}
							}
						} catch (Exception e) {
							AlertUtil.showErrorAlert(e.getMessage());
							LOG.error("打开连接失败!!!" + e);
						}
					});
					MenuItem item1 = new MenuItem("关闭连接");
					item1.setOnAction(event1 -> {
						treeItem.getChildren().clear();
					});
					MenuItem item3 = new MenuItem("修改连接");
					item3.setOnAction(event1 -> {
						updateOfDatabaseConfig = (DatabaseConfig) treeItem.getGraphic().getUserData();
						if (updateOfDatabaseConfig != null) {
							LOG.debug("打开修改数据库连接窗口...");
							UpdateConnection controller = (UpdateConnection) loadFXMLPage("修改数据库连接", FXMLPage.UPDATE_CONNECTION, false);
							controller.setIndexController(this);
							controller.init();
							controller.showDialogStage();
						}
					});
					MenuItem item2 = new MenuItem("删除连接");
					item2.setOnAction(event1 -> {
						if (AlertUtil.showConfirmAlert("确定删除该连接吗")) {
							return;
						}
						LOG.debug("执行删除数据库链接...");
						DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData();
						try {
							ConfigUtil.deleteDatabaseConfig(selectedConfig.getConnName());
							this.loadTVDataBase();
						} catch (Exception e) {
							AlertUtil.showErrorAlert("删除数据库连接失败: " + e.getMessage());
							LOG.error("删除数据库连接失败!!!" + e);
						}
					});
					cell.setContextMenu(contextMenu);
				}
				// 加载所有表
				if (event.getClickCount() == 2) {
					if (treeItem == null) {
						return;
					}
					treeItem.setExpanded(true);
					if (level == 1) {
						LOG.debug("加载所有表....");
						DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData();
						try {
							List<String> tables = DBUtil.getTableNames(selectedConfig);
							if (!tables.isEmpty()) {
								ObservableList<TreeItem<String>> children = cell.getTreeItem().getChildren();
								children.clear();
								// 获得树节点
								for (String tableName : tables) {
									TreeItem<String> newTreeItem = new TreeItem<>();
									ImageView imageView = new ImageView("image/table.png");
									imageView.setFitHeight(18);
									imageView.setFitWidth(18);
									newTreeItem.setGraphic(imageView);
									newTreeItem.setValue(tableName);
									children.add(newTreeItem);
								}
							}
							LOG.debug("加载所有表成功!");
						} catch (Exception e) {
							AlertUtil.showErrorAlert(e.getMessage());
							LOG.error("加载所有表失败!!!" + e);
						}
					} else if (level == 2) {
						LOG.debug("将表的数据加载到数据面板...");
						String tableName = treeCell.getTreeItem().getValue();
						DatabaseConfig databaseConfig = (DatabaseConfig) treeItem.getParent().getGraphic().getUserData();
						this.databaseConfig = databaseConfig;
						String oldTxtConnName = txtConnName.getText();
						txtConnName.setText(databaseConfig.getConnName());
						//同一个库可以选择多个表，不同的库选择最后选择的那个表
						if(oldTxtConnName == null || oldTxtConnName.isEmpty()) {
							txtTableName.setText(tableName);
						} else {
							if(oldTxtConnName.equals(databaseConfig.getConnName())) {
								String oldTxtTableName = txtTableName.getText();
								if(oldTxtTableName == null || oldTxtTableName.isEmpty()) {
									txtTableName.setText(tableName);
								} else {
									if(!("," + oldTxtTableName + ",").contains(("," + tableName + ","))) {
										txtTableName.setText(tableName + "," + oldTxtTableName);
									}
								}
							} else {
								txtTableName.setText(tableName);
							}
						}
						String cnt = cboNameCnt.getValue();
						String tableNames = txtTableName.getText();
						StringBuilder stringBuilder = new StringBuilder();
						for (String name : tableNames.split(",")) {
							String pascalTableName = StrUtil.unlineToPascal(name, Integer.parseInt(cnt));
							stringBuilder.append(pascalTableName).append(",");
						}
						if(!stringBuilder.isEmpty()) {
							stringBuilder.deleteCharAt(stringBuilder.length() - 1);
						}
						txtEntityName.setText(stringBuilder.toString());
						LOG.debug("将表的数据加载到数据面板成功!");
					}
				}
			});
			return cell;
		});
	}

	/**
	 * 加载数据库到树集
	 */
	public void loadTVDataBase() {
		TreeItem<String> rootTreeItem = tvDataBase.getRoot();
		rootTreeItem.getChildren().clear();
		List<DatabaseConfig> item = ConfigUtil.getDatabaseConfig();
		for (DatabaseConfig dbConfig : item) {
			TreeItem<String> treeItem = new TreeItem<>();
			treeItem.setValue(dbConfig.getConnName());
			ImageView dbImage = new ImageView("image/database.png");
			dbImage.setFitHeight(20);
			dbImage.setFitWidth(20);
			dbImage.setUserData(dbConfig);
			treeItem.setGraphic(dbImage);
			rootTreeItem.getChildren().add(treeItem);
		}
	}

	/**
	 * 使用说明
	 */
	public void onInstructions(MouseEvent event) {
		AboutUsController controller = (AboutUsController) loadFXMLPage("使用说明", FXMLPage.ABOUT, false, false);
		controller.showDialogStage();
	}

	/**
	 * 执行创建
	 */
	public void onCreate(ActionEvent event) {
		LOG.debug("执行创建...");
		if(!validTextField()) {
			return;
		}
		CodeFromTemplateFile.generateCommonFileCode(txtMainPath.getText());
		ParamInfo paramInfo = new ParamInfo();
		paramInfo.setCnt(cboNameCnt.getValue());
		paramInfo.setCorePath(txtMainPath.getText());
		paramInfo.setProjectPath(txtProjectPath.getText());
		String[] tableNames = txtTableName.getText().split(",");
		int total = 0;
		for (String name : tableNames) {
			paramInfo.setTableName(name.trim());
			List<Map<String, String>> tableColumns;
			List<String> tablePrimaryKeyList;
			String tableRemark;
			try {
				tableColumns = DBUtil.getTableColumns(databaseConfig, name);
				tablePrimaryKeyList = DBUtil.getTablePrimaryKey(databaseConfig, name);
				tableRemark = Optional.ofNullable(DBUtil.getTableAttribute(databaseConfig, name)).orElse("");
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
			if (tableColumns.isEmpty() || tablePrimaryKeyList.isEmpty()) {
				AlertUtil.showErrorAlert("表" + name + "的列为空或者主键列为空");
				return;
			}
			paramInfo.setTableRemarks(tableRemark);
			paramInfo.setCustomCode(new DefaultCustomCodeImpl(tableColumns, tablePrimaryKeyList, name.trim()));
			int cnt = CodeFromTemplateFile.generateModuleFileCode(paramInfo);
			total += cnt;
		}
		AlertUtil.showInfoAlert("生成代码成功！生成文件个数为：" + total);
	}

	private boolean validTextField() {
		if (txtMainPath.getText().isEmpty()) {
			AlertUtil.showErrorAlert("common所在目录不能为空");
			return false;
		}
		if (txtProjectPath.getText().isEmpty() || !(txtProjectPath.getText() + "/").contains(txtMainPath.getText() + "/")) {
			AlertUtil.showErrorAlert("common所在目录是选择的目录或者包含选择的目录");
			return false;
		}
		if(txtTableName.getText().isEmpty()) {
			AlertUtil.showErrorAlert("表名不能为空");
			return false;
		}
		return true;
	}

	public void onShowString(ActionEvent event) {
		if(!validTextField()) {
			return;
		}
		CodeStrController controller
				= (CodeStrController) loadFXMLPage("展示生成的代码字符串", FXMLPage.CODE_STR, false, false);
		controller.setTableNames(txtTableName.getText());

		ParamInfo paramInfo = new ParamInfo();
		paramInfo.setCnt(cboNameCnt.getValue());
		paramInfo.setCorePath(txtMainPath.getText());
		paramInfo.setProjectPath(txtProjectPath.getText());
		String[] tableNames = txtTableName.getText().split(",");
		StringBuilder sb = new StringBuilder();
		for (String name : tableNames) {
			paramInfo.setTableName(name.trim());
			List<Map<String, String>> tableColumns;
			List<String> tablePrimaryKeyList;
			try {
				tableColumns = DBUtil.getTableColumns(databaseConfig, name);
				tablePrimaryKeyList = DBUtil.getTablePrimaryKey(databaseConfig, name);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
			paramInfo.setCustomCode(new DefaultCustomCodeImpl(tableColumns, tablePrimaryKeyList, name.trim()));
			String txtShowStr = getString(paramInfo);
			sb.append(txtShowStr).append("\n\n");
		}
		controller.setTxtShowString(sb.toString());
		controller.showDialogStage();
	}

	private String getString(ParamInfo paramInfo) {
		String tableName = paramInfo.getTableName();
		CustomCode customCode = paramInfo.getCustomCode();
		String alias = Optional.ofNullable(txtAliasName.getText()).orElse("");
		String strType = cboStringType.getValue();
		return switch (strType) {
			case "resultMapList" -> tableName + ":\n" + customCode.getResultMapList();
			case "fieldVOList" -> tableName + ":\n" + customCode.getFieldVOList();
			case "fieldEntityList" -> tableName + ":\n" + customCode.getFieldEntityList();
			case "entityToVOSetterFields" -> tableName + ":\n" + customCode.getEntityToVOSetterFields();
			case "voToEntitySetterFields" -> tableName + ":\n" + customCode.getVOToEntitySetterFields();
			case "insertValueList" -> tableName + ":\n" + customCode.getInsertValueList();
			case "whereIds" -> tableName + ":\n" + customCode.getWhereIds();
			case "whereIfList" -> tableName + ":\n" + customCode.getWhereIfList(alias);
			case "columnListWithAlias" -> tableName + ":\n" + customCode.getColumnListWithAlias(alias);
			case "setIfList" -> tableName + ":\n" + customCode.getSetIfList();
			default -> tableName + ":\n";
		};
	}

	/**
	 * 清空表名称
	 */
	public void onClearTable(ActionEvent event) {
		txtTableName.setText("");
	}

	/**
	 * 数据库连接
	 */
	public void onConnection(MouseEvent event) {
		ConnectionController controller = (ConnectionController) loadFXMLPage("新建数据库连接", FXMLPage.CONNECTION, false);
		controller.setIndexController(this);
		controller.showDialogStage();
	}

	/**
	 * 选择项目文件
	 */
	public void onSelectProjectPath(ActionEvent event) {
		DirectoryChooser directoryChooser = new DirectoryChooser();
		File file = directoryChooser.showDialog(super.getPrimaryStage());
		if (file != null) {
			String path = file.getPath();
			path = path.replace("\\", "/");
			LOG.debug("选择文件项目目录:" + path);
			txtProjectPath.setText(path);
			txtBasePackage.setText(StrUtil.getBasePackage(path));
			String corePath = path.substring(0, path.lastIndexOf("/"));
			txtMainPath.setText(corePath);
			txtCorePackage.setText(StrUtil.getBasePackage(corePath));
		}
	}

	/**
	 * 获得更新数据库选择的配置文件
	 */
	public DatabaseConfig getUpdateOfDatabaseConfig() {
		return updateOfDatabaseConfig;
	}

}
